package com.leyou.user.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.auth.dto.Payload;
import com.leyou.auth.dto.UserDetail;
import com.leyou.auth.utils.JwtUtils;
import com.leyou.common.constants.RegexPatterns;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.RegexUtils;
import com.leyou.user.dto.UserDTO;
import com.leyou.user.entity.User;
import com.leyou.user.mapper.UserMapper;
import com.leyou.user.service.UserService;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.SMS_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.VERIFY_CODE_KEY;

/**
 * @author YYP
 * @date 2021/1/9
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService  {

    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;


    private final String KEY_PREFIX = "ly:sms:phone:";



    /* @Autowired
    private JwtUtils jwtUtils;*/
/*    *//**
     * 展示用户信息
     * @param token
     * @return
     *//*
    @Override
    public UserDetail showUser(String token) {
        UserDetail userDetail = null;
        try {
            //此处,只要pom依赖ly-auth-api,且在yml中配置了clientid与secret,
            // 可以自动使auth-api中的配置类AuthConfiguration生效,进而先请求auth-service获取到key,然后注册jwtutils为bean
            Payload payload = this.jwtUtils.parseJwt(token);
            userDetail = payload.getUserDetail();
        } catch (Exception e) {
            throw new LyException(401,"用户未登陆");
        }
        return userDetail;
    }*/

    /**
     * 将手机号与生成的code发送到mq
     * @param phone
     */
    @Override
    public void sendVerifyCode(String phone) {
        //判断手机号格式
        if (!RegexUtils.isPhone(phone)) {
            throw new LyException(400,"手机号格式错误");
        }
        //1.手机号 2.验证码
        HashMap<String, String> msg = new HashMap<>();
        //生成验证码
        String code = RandomStringUtils.randomNumeric(6);
        msg.put("phone",phone);
        msg.put("code",code);

        //amqp,发送到mq队列中
        amqpTemplate.convertAndSend(SMS_EXCHANGE_NAME,VERIFY_CODE_KEY,msg);

        //存入redis,确保唯一性,加前缀
        redisTemplate.opsForValue().set(KEY_PREFIX+phone,code,5, TimeUnit.MINUTES);
    }

    /**
     * 判断信息是否存在,
     * @param data 要校验的数据
     * @param type 数据的类型,1 用户名, 2 手机号
     * @return
     */
    @Override
    public Boolean isExistsData(String data, Integer type) {
        //取值只能为1,2;data不为空;type为手机号但是格式不对
        if ((type!=1 && type!=2) || StringUtils.isEmpty(data) || (type == 2 && !RegexUtils.isPhone(data))) {
            throw new LyException(400,"请求参数错误");
        }
        String colName = null;
        switch (type) {
            case 1:
                colName = "username";
                break;
            case 2:
                colName= "phone";
                break;
        }
        return this.query().eq(colName,data).count() == 1;

    }

    /**
     * 根据用户密码查询
     * @param username
     * @param password
     * @return
     */
    @Override
    public UserDTO queryUser(String username, String password) {
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
           throw new LyException(400,"用户名或密码不能为空");

        }
        User user = this.query().eq("username", username).one();
        if (user == null) {
            throw new LyException(400,"用户名不存在");
        }
        //验证密码
        if (!passwordEncoder.matches(password,user.getPassword() )){
            throw new LyException(400,"密码错误");
        }
        return new UserDTO(user) ;
    }

    /**
     * 注册
     * @param code
     */
    @Override
    @Transactional
    public void registerUser(User user, String code) {

        //校验验证码是否为空
        if (StringUtils.isEmpty(code)) {
            throw new LyException(400,"验证码不存在");
        }

        //从redis中获取code
        String key = KEY_PREFIX+user.getPhone();
        System.out.println("key = " + key);
        //判断key不存在或者验证码不匹配
        if (!redisTemplate.hasKey(key) || !code.equals(redisTemplate.opsForValue().get(key))){
            throw new LyException(400,"验证码失效");
        }

        //对密码进行加密，md5加盐加密，盐值在算法中，每一次的盐值都不相同
        String encodePwd = passwordEncoder.encode(user.getPassword());
        //先根据密文推算出盐值，然后明文+盐值，加密，再次比较新密文和密文
        //passwordEncoder.matches("明文","密文");

        //存入数据库
        user.setPassword(encodePwd);
        this.save(user);

    }
}
